/**
 * Copyright [2019] [LiBo/Alex of copyright liboware@gmail.com ]
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hyts.infodb.toolkit.monitor;

import com.alibaba.fastjson.JSONObject;
import com.hyts.infodb.utils.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @project-name:infodb
 * @package-name:com.hyts.infodb.toolkit.monitor
 * @author:LiBo/Alex
 * @create-date:2020-03-05 10:30
 * @copyright:libo-alex4java
 * @email:liboware@gmail.com
 * @description: http请求操作得动态代理拦截aop统计计算操作
 */

@Slf4j
@Aspect
@Component
public class HttpRequestMonitor {



    // 声明前置通知
    @Around("@annotation(com.hyts.infodb.toolkit.monitor.HttpMonitor)")
    public Object monitor(ProceedingJoinPoint joinPoint) {
        /**
         * 时间戳校验,超过一分钟,拦截
         */
        log.info(getMethodInfo(joinPoint));
        //1.这里获取到所有的参数值的数组
        Object[] args = joinPoint.getArgs();
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        //2.最关键的一步:通过这获取到方法的所有参数名称的字符串数组
        String[] parameterNames = methodSignature.getParameterNames();
        try {
            //3.通过你需要获取的参数名称的下标获取到对应的值
            int timeStampIndex = ArrayUtils.indexOf(parameterNames, "timeStamp");
            if (timeStampIndex != -1) {
                long timeStamp = (Long) args[timeStampIndex];
                if (System.currentTimeMillis() - timeStamp > 60000) {
//                    rst.setResultCode(rst.resultCode_hashCode_overdue);
//                    rst.setReturnMsg("时间戳过期");
//                    rst.setReturnObject("时间戳过期");
//                    return rst;
                }
            }
            log.info("操作服务拦截aop{}",ServletUtil.getRequest().getRequestURL());
            return joinPoint.proceed();
        } catch (Throwable throwable) {
            log.error("时间戳校验异常");
            throwable.printStackTrace();
//            rst.setResultCode(rst.resultCode_error);
//            rst.setReturnMsg("AOP校验异常");
//            rst.setReturnObject("AOP校验异常");
            //return rst;
            try {
                return joinPoint.proceed();
            } catch (Throwable throwable1) {
                return null;
            }
        }
    }

    /**
     * 获取方法信息操作
     * @param point
     * @return
     */
    private String getMethodInfo(JoinPoint point) {
        ConcurrentHashMap<String, Object> info = new ConcurrentHashMap<>(3);

        info.put("class", point.getTarget().getClass().getSimpleName());
        info.put("method", point.getSignature().getName());

        String[] parameterNames = ((MethodSignature) point.getSignature()).getParameterNames();
        ConcurrentHashMap<String, String> args = null;

        if (Objects.nonNull(parameterNames)) {
            args = new ConcurrentHashMap<>(parameterNames.length);
            for (int i = 0; i < parameterNames.length; i++) {
                String value = point.getArgs()[i] != null ? point.getArgs()[i].toString() : "null";
                args.put(parameterNames[i], value);
            }
            info.put("args", args);
        }

        return JSONObject.toJSONString(info);
    }
}
